﻿using AppMonitor.Bex;
using AppMonitor.Model;
using AppMonitor.Plugin;
using AppMonitor.Plugin.Zookeeper;
using log4net;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace AppMonitor.Froms
{
    public partial class DubboMonitorForm : MonitorBaseForm
    {
        private static ILog logger = LogManager.GetLogger("LogFileAppender");
        MonitorForm monitorForm = null;
        MonitorItemConfig itemConfig = null;
        SessionConfig seConfig;
        YSTools.YSHttpUtility http = new YSTools.YSHttpUtility();
        int timer = 30, resetTimer = 30, firstTimer = 0, ftime = 3;
        bool check_flag = false, isfirst = true;
        bool get_srvxml_run = false, zookrun = false;
        CZookeeper zook = null;
        List<string> nodeList = new List<string>();
        string formTag = "";

        public DubboMonitorForm(MonitorForm _form, SessionConfig _config, MonitorItemConfig _itemConfig, int index)
        {
            InitializeComponent();
            monitorForm = _form;
            seConfig = _config;
            itemConfig = _itemConfig;
            timer = AppConfig.Instance.MConfig.MonitorTimer + index * 3;
            resetTimer = timer;
            progressBar1.Maximum = timer;
            ftime = 3 + index * 3;
        }

        public override void CloseForm()
        {
            this.Close();
        }

        private void DubboMonitorForm_Load(object sender, EventArgs e)
        {
            formTag = this.Tag.ToString();
            ReflushMonitorItem();

            RenderCustomShellList();

            // 初始化Zookeeper连接
            initZookeeper();

            // 启动定时器
            timer1.Enabled = true;
            timer1.Start();
        }

        public override void ReflushMonitorItem()
        {
            l_appname.Text = itemConfig.dubbo.AppName;
            string srcdir = itemConfig.dubbo.DubboSrvDir;
            if (srcdir != null)
            {
                if (!srcdir.EndsWith("/"))
                    srcdir += "/";
                l_pro_path.Text = srcdir;
            }
            l_server_package.Text = itemConfig.dubbo.PackageName;
            l_ctl_path.Text = itemConfig.dubbo.CtlshPath;
            l_dubbo_disconfig.Text = itemConfig.dubbo.DisconfigUrl;
        }

        #region 定时任务
        public void RenderCustomShellList()
        {
            customShellListView.Items.Clear();
            ListViewItem item = null;
            ListViewItem.ListViewSubItem subItem = null;
            foreach (CmdShell cmds in seConfig.CustomShellList)
            {
                if (cmds.Target == itemConfig.dubbo.Uuid)
                {
                    item = new ListViewItem();
                    item.Tag = cmds;
                    item.Name = cmds.Name;
                    item.Text = cmds.Name;

                    subItem = new ListViewItem.ListViewSubItem();
                    subItem.Text = cmds.Type;
                    item.SubItems.Add(subItem);

                    customShellListView.Items.Add(item);
                }
            }
        }

        public void checkTimedTask()
        {
            var now = DateTime.Now;
            String[] dts = null;
            string week = "";
            foreach (CmdShell cmds in seConfig.CustomShellList)
            {
                if (cmds.Target == itemConfig.dubbo.Uuid)
                {
                    if (cmds.TaskType == TaskType.Timed)
                    {
                        if (null != cmds.ShellList)
                        {
                            dts = null;
                            foreach (TaskShell task in cmds.ShellList)
                            {
                                dts = task.DateTime.Split('|');
                                if (dts[0] == "0")
                                {// 一次
                                    if (now.ToString("yyyy-MM-dd") == dts[1] && now.ToString("HH:mm:ss") == dts[2])
                                    {
                                        // 执行
                                        runTaskShell(cmds, task);
                                    }
                                }
                                else if (dts[0] == "1")
                                {// 每天
                                    if (now.ToString("HH:mm:ss") == dts[2])
                                    {
                                        // 执行
                                        runTaskShell(cmds, task);
                                    }
                                }
                                else if (dts[0] == "2")
                                {// 每周
                                    week = DateTime.Now.DayOfWeek.ToString("d");
                                    if (dts[1].Contains(week) && now.ToString("HH:mm:ss") == dts[2])
                                    {
                                        // 执行
                                        runTaskShell(cmds, task);
                                    }
                                }
                                else if (dts[0] == "3")
                                {// 每月
                                    if (now.ToString("dd") == dts[1] && now.ToString("HH:mm:ss") == dts[2])
                                    {
                                        // 执行
                                        runTaskShell(cmds, task);
                                    }
                                }
                                else if (dts[0] == "4")
                                {// 每年
                                    if (now.ToString("MM-dd") == dts[1] && now.ToString("HH:mm:ss") == dts[2])
                                    {
                                        // 执行
                                        runTaskShell(cmds, task);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        public void runTaskShell(CmdShell cmds, TaskShell task)
        {
            ThreadPool.QueueUserWorkItem((a) =>
            {

                string srvdir = itemConfig.dubbo.DubboSrvDir;
                if (null != srvdir)
                {
                    if (!srvdir.EndsWith("/"))
                    {
                        srvdir += "/";
                    }
                }

                string shell = task.Shell;
                if (shell.Contains("{dubbosrv_dir}"))
                {
                    shell = shell.Replace("{dubbosrv_dir}", srvdir);
                }

                if (shell.Contains("{server_name}"))
                {
                    shell = shell.Replace("{server_name}", l_server_package.Text);
                }

                if (shell.Contains("{adminsh}"))
                {
                    shell = shell.Replace("{adminsh}", srvdir + "bin/admin.sh");
                }
                shell = shell.Replace("//", "/");

                monitorForm.RunShell(shell, false);
            });
        }
        #endregion


        private void timer1_Tick(object sender, EventArgs e)
        {
            if (timer < 1)
            {
                if (!check_flag)
                {
                    SetStatus(0);
                }
                CheckDubboServer();
            }
            if (isfirst)
            {
                if (firstTimer < ftime)
                {
                    firstTimer++;
                }
                else
                {
                    isfirst = false;
                    CheckDubboServer();
                }
            }

            timer--;
            progressBar1.Value = timer;

            // 检查定时任务
            checkTimedTask();
        }

        private void button5_Click(object sender, EventArgs e)
        {
            CheckDubboServer();
        }

        public void initZookeeper()
        {
            if (zook == null)
            {
                zook = new CZookeeper(itemConfig.dubbo.ConnectionStr, new ZooWatcher());
            }
        }

        public void CheckDubboServer()
        {
            try
            {
                timer = resetTimer;
                progressBar1.Value = timer;

                if (!zookrun && !string.IsNullOrWhiteSpace(itemConfig.dubbo.Port))
                {
                    zookrun = true;
                    bool result = false;
                    //将IP和端口替换成为你要检测的

                    string ipAddress = seConfig.Host;
                    int portNum = Convert.ToInt32(itemConfig.dubbo.Port);
                    IPAddress ip = IPAddress.Parse(ipAddress);
                    try
                    {
                        IPEndPoint point = new IPEndPoint(ip, portNum);
                        using (Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
                        {
                            sock.Connect(point);
                            result = true;
                            logger.Debug("连接成功:" + point);                            
                            sock.Close();
                        }
                    }
                    catch (SocketException e)
                    {
                        logger.Error("连接失败：" + portNum, e);
                    }
                    zookrun = false;
                    SetStatus(result ? 1 : 0);                                        
                }
            }
            catch (Exception e)
            {
                logger.Error("CheckIceServer--" + e.Message, e);
            }
        }

        public void SetStatus(int status)
        {
            check_flag = true;
            try
            {
                this.BeginInvoke((MethodInvoker)delegate()
                {
                    string uuid = itemConfig.dubbo.Uuid;
                    if (status > 0)
                    {
                        itemConfig.dubbo.RunStatus = RunState.Normal;
                        pic_run_state.BackgroundImage = Properties.Resources.green_light_48;
                        label_status.Text = "程序运行正常";
                        this.skinToolTip1.SetToolTip(pic_run_state, label_status.Text);
                        btn_start.Enabled = false;
                        btn_stop.Enabled = true;
                        link_service_list.Visible = true;

                        monitorForm.SetNodeIcon("task-" + uuid, 1);
                    }
                    else
                    {
                        itemConfig.dubbo.RunStatus = RunState.AbNormal;
                        pic_run_state.BackgroundImage = Properties.Resources.org_light_48;
                        label_status.Text = "程序无法访问";
                        this.skinToolTip1.SetToolTip(pic_run_state, "程序无法访问，请检查问题");
                        btn_start.Enabled = true;
                        btn_stop.Enabled = false;
                        link_service_list.Visible = false;

                        monitorForm.SetNodeIcon("task-" + uuid, 2);
                    }
                });
            }catch(Exception ex){
                logger.Error("SetStatus Error：" + ex.Message, ex);
                if (ex.Message.Contains("在创建窗口句柄之前，不能在控件上调用"))
                {
                    timer1.Stop();
                    timer1.Dispose();
                }
            }            
        }


        private void btn_start_Click(object sender, EventArgs e)
        {
            btn_start.Enabled = false;
            string path = itemConfig.dubbo.CtlshPath;
            string dir = path.Substring(0, path.LastIndexOf("/") + 1);
            string ctrl = "." + path.Substring(path.LastIndexOf("/"));
            monitorForm.RunShell("cd " + dir, false, true);
            monitorForm.RunShell(ctrl + " start", false, true);
        }

        private void btn_stop_Click(object sender, EventArgs e)
        {
            btn_stop.Enabled = false;
            monitorForm.RunShell(itemConfig.dubbo.CtlshPath + " stop", false, true);
        }

        private void btn_restart_Click(object sender, EventArgs e)
        {
            btn_start.Enabled = false;
            btn_stop.Enabled = false;
            string path = itemConfig.dubbo.CtlshPath;
            string dir = path.Substring(0, path.LastIndexOf("/") + 1);
            string ctrl = "." + path.Substring(path.LastIndexOf("/"));
            monitorForm.RunShell("cd " + dir, false, true);
            monitorForm.RunShell(ctrl + " restart", false, true);
        }

        private void 自定义命令ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CustomShellForm form = new CustomShellForm(seConfig, itemConfig.dubbo.Uuid);
            form.ShowDialog(this);

            RenderCustomShellList();
        }

        private void customShellListView_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (customShellListView.SelectedItems.Count > 0)
            {
                ListViewItem item = customShellListView.SelectedItems[0];
                if (null != item)
                {
                    CmdShell cmds = (CmdShell)item.Tag;
                    StringBuilder sb = new StringBuilder();
                    foreach (TaskShell task in cmds.ShellList)
                    {
                        if (cmds.TaskType == TaskType.Default)
                        {
                            sb.AppendLine(task.Shell);
                        }
                        else if (cmds.TaskType == TaskType.Timed)
                        {
                            sb.AppendLine(string.Format("{0} - {1}", task.DateTime, task.Shell));
                        }
                        else if (cmds.TaskType == TaskType.Condition)
                        {
                            sb.AppendLine(string.Format("{0} - {1}", cmds.Condition, task.Shell));
                        }
                    }
                    shellView.Text = sb.ToString();
                    if (cmds.TaskType == TaskType.Default)
                    {
                        btn_run.Enabled = true;
                    }
                    return;
                }
            }
            btn_run.Enabled = false;
            shellView.Text = "";
        }

        private void button6_MouseUp(object sender, MouseEventArgs e)
        {
            contextMenu.Show(custom_btn, new Point(e.X, e.Y));
        }

        private void btn_run_Click(object sender, EventArgs e)
        {
            string cmdstr = shellView.Text;
            if (!string.IsNullOrWhiteSpace(cmdstr))
            {
                string[] cmdArr = cmdstr.Split('\n');
                foreach (string cmd in cmdArr)
                {
                    monitorForm.RunShell(cmd.Trim(), true, true);
                    Thread.Sleep(100);
                }
            }
        }

        private void CustomTimeTask_Click(object sender, EventArgs e)
        {
            TimedTaskForm form = new TimedTaskForm(itemConfig.dubbo.Index);
            form.setCallback(new TimedTaskForm.AsyncCallback(addTimedTaskFinish));
            form.ShowDialog(this);
        }

        public void addTimedTaskFinish(CmdShell cs)
        {
            cs.Target = itemConfig.dubbo.Uuid;

            seConfig.CustomShellList.Add(cs);

            AppConfig.Instance.SaveConfig(2);

            RenderCustomShellList();
        }

        private void 条件任务ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ConditionTaskForm form = new ConditionTaskForm(seConfig, itemConfig.dubbo.Index);
            form.setCallback(new ConditionTaskForm.AsyncCallback(addConditionTaskFinish));
            form.ShowDialog(this);
        }

        public void addConditionTaskFinish(CmdShell cs)
        {
            cs.Target = itemConfig.dubbo.Uuid;

            seConfig.CustomShellList.Add(cs);

            AppConfig.Instance.SaveConfig(2);

            RenderCustomShellList();
        }

        private void customShellListView_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right && customShellListView.SelectedItems.Count > 0)
            {
                contextMenuStrip2.Show(customShellListView, e.Location);
            }
        }

        private void toolStripMenuItem2_Click(object sender, EventArgs e)
        {
            try
            {
                ListViewItem item = customShellListView.SelectedItems[0];
                CmdShell cmds = (CmdShell)item.Tag;
                if (cmds.TaskType == TaskType.Default)
                {
                    CustomShellForm form = new CustomShellForm(seConfig, itemConfig.dubbo.Uuid);
                    form.SetUpdater(cmds);
                    form.ShowDialog(this);

                    shellView.Text = "";
                    btn_run.Enabled = false;
                    RenderCustomShellList();
                }
                else if (cmds.TaskType == TaskType.Timed)
                {
                    TimedTaskForm form = new TimedTaskForm(itemConfig.dubbo.Index);
                    form.setCallback(new TimedTaskForm.AsyncCallback(editTaskFinish));
                    form.SetUpdater(cmds);
                    form.ShowDialog(this);
                }
                else if (cmds.TaskType == TaskType.Condition)
                {
                    ConditionTaskForm form = new ConditionTaskForm(seConfig, itemConfig.dubbo.Index);
                    form.setCallback(new ConditionTaskForm.AsyncCallback(editTaskFinish));
                    form.SetUpdater(cmds);
                    form.ShowDialog(this);
                }
            }
            catch { }
        }

        public void editTaskFinish(CmdShell cs)
        {
            shellView.Text = "";
            btn_run.Enabled = false;

            AppConfig.Instance.SaveConfig(2);
            RenderCustomShellList();
        }

        private void toolStripMenuItem3_Click(object sender, EventArgs e)
        {
            if (customShellListView.SelectedItems.Count > 0)
            {
                try
                {
                    ListViewItem item = customShellListView.SelectedItems[0];
                    DialogResult dr = MessageBox.Show(this, "您确定要删除此项吗？", "警告", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
                    if (dr == System.Windows.Forms.DialogResult.OK)
                    {
                        customShellListView.Items.Remove(item);
                        CmdShell cmds = (CmdShell)item.Tag;
                        seConfig.CustomShellList.Remove(cmds);

                        AppConfig.Instance.SaveConfig(2);
                    }
                }
                catch { }
            }
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            try
            {
                if (get_srvxml_run)
                {
                    return;
                }
                get_srvxml_run = true;

                string targetxml = MainForm.TEMP_DIR + string.Format("srv-{0}.xml", DateTime.Now.ToString("MMddHHmmss"));
                targetxml = targetxml.Replace("\\", "/");
                string serverxml = string.Format("{0}config/{1}.xml", l_pro_path.Text, l_appname.Text);

                TextEditorForm editor = new TextEditorForm();
                editor.Show(this);

                editor.LoadRemoteFile(new ShellForm(monitorForm), serverxml, targetxml);
            }
            catch { }

            get_srvxml_run = false;
        }

        private void visitToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            DubboDeployVersionForm form = new DubboDeployVersionForm(monitorForm, seConfig, itemConfig.dubbo);
            form.ShowDialog(this);
        }

        private void link_service_list_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (null != nodeList && nodeList.Count > 0)
            {
                ZookeeperForm form = new ZookeeperForm(zook, nodeList);
                form.Show();
            }
            else
            {
                new Thread((ThreadStart)delegate()
                {
                    try
                    {
                        IEnumerable<string> list = zook.GetNodeChildren("/dubbo", false);
                        if (list != null)
                        {
                            nodeList.Clear();
                            foreach (string node in list)
                            {
                                if (node.StartsWith(itemConfig.dubbo.PackageName))
                                {
                                    nodeList.Add(node);
                                }
                            }

                            this.BeginInvoke((MethodInvoker)delegate() {
                                ZookeeperForm form = new ZookeeperForm(zook, nodeList);
                                form.Show();
                            });                            
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.Error("Get Zookeeper Nodes Error:" + ex.Message, ex);
                    }
                }).Start();
            }
        }

        private void DubboMonitorForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            timer1.Stop();
            timer1.Dispose();
        }

    }
}
